﻿using Common.Exceptions;
using Common.Utils;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;

namespace WallpaperApi.Middleware
{
    /// <summary>
    /// 全局异常处理中间件
    /// 用于捕获应用程序中所有未处理的异常，并返回统一的错误响应格式
    /// </summary>
    public class GlobalExceptionHandlerMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<GlobalExceptionHandlerMiddleware> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="next">下一个中间件委托</param>
        /// <param name="logger">日志记录器</param>
        public GlobalExceptionHandlerMiddleware(RequestDelegate next, ILogger<GlobalExceptionHandlerMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        /// <summary>
        /// 中间件执行方法
        /// </summary>
        /// <param name="context">HTTP上下文</param>
        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                // 执行下一个中间件
                await _next(context);
            }
            catch (Exception ex)
            {
                // 捕获所有异常并处理
                await HandleExceptionAsync(context, ex);
            }
        }

        /// <summary>
        /// 异常处理方法
        /// </summary>
        /// <param name="context">HTTP上下文</param>
        /// <param name="exception">异常对象</param>
        private async Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            // 检查响应是否已经开始
            if (context.Response.HasStarted)
            {
                _logger.LogWarning("响应已开始，跳过全局异常处理");
                return;
            }

            context.Response.ContentType = "application/json";
            ApiResponse<object> result;
            int statusCode;

            // 原有的异常处理逻辑保持不变
            switch (exception)
            {
                case BusinessException businessEx:
                    _logger.LogWarning("业务异常: {Message}", businessEx.Message);
                    statusCode = (int)businessEx.StatusCode;
                    result = ApiResponse<object>.Fail(businessEx.Message, businessEx.BusinessCode);
                    break;

                case DbUpdateException dbEx when dbEx.InnerException is SqlException sqlEx:
                    statusCode = HandleSqlException(sqlEx, out string errorMessage);
                    result = ApiResponse<object>.Fail(errorMessage, statusCode);
                    break;
             

                case ArgumentException argEx:
                    _logger.LogWarning("参数异常: {Message}", argEx.Message);
                    statusCode = 400;
                    result = ApiResponse<object>.Fail(argEx.Message, 400);
                    break;

                default:
                    _logger.LogError(exception, "未处理的系统异常");
                    statusCode = 500;
                    result = ApiResponse<object>.Fail("系统内部错误", 500);
                    break;
            }

            context.Response.StatusCode = statusCode;
            var json = JsonSerializer.Serialize(result);
            await context.Response.WriteAsync(json);
        }

        /// <summary>
        /// 处理 SQL Server 特定异常
        /// </summary>
        private int HandleSqlException(SqlException sqlEx, out string errorMessage)
        {
            _logger.LogError(sqlEx, "数据库异常 - 错误码: {ErrorNumber}", sqlEx.Number);

            switch (sqlEx.Number)
            {
                case 547: // 外键约束冲突
                    errorMessage = "关联数据不存在，请检查分类是否正确";
                    return 400;

                case 2601: // 唯一索引冲突
                case 2627:
                    errorMessage = "数据已存在，请勿重复添加";
                    return 400;

                case 18456: // 登录失败
                case 4060:  // 无法打开数据库
                    errorMessage = "数据库连接失败";
                    return 500;

                case 1205:  // 死锁
                    errorMessage = "系统繁忙，请稍后重试";
                    return 500;

                default:
                    errorMessage = "数据库操作失败";
                    return 500;
            }
        }
    }
}